const LinkedList = require('../linked-list/linkedList');

const defaultHashTableSize = 32;
module.exports = class HashTable {
  constructor() {
    // 构建默认大小的buckets，使用链表主要用来解决hash冲突的情况，如果每一个bucket存放
    // 单独一个hash，就必须要保证经过散列函数处理的hash必须是唯一的，这也会带来时间成本
    this.buckets = Array(defaultHashTableSize)
      .fill(null)
      .map(() => new LinkedList());

    this.keys = Object.create(null);
  }
  hash(key) {
    // 遍历key的每个字符，获取到对应的ASC码，相加得到一个hash值
    // 例如：key = 'cuvee'，对应的hash为 99 + 117 + 118 + 101 + 101 = 534
    const hash = Array.from(key).reduce((acc, cur) => {
      return acc + cur.chaCodeAt(0);
    }, 0);
    // 最终的hash值对默认buckets大小取余
    // 534 % 32 = 22，cuvee这个key对应的value将存放在buckets[22]对应的链表当中
    return hash % defaultHashTableSize;
  }

  set(key, value) {
    const keyHash = this.hash(key);
    this.keys[key] = keyHash;

    const bucketLinkedList = this.buckets[keyHash];
    const node = bucketLinkedList.find(value);

    if (!node) {
      bucketLinkedList.append({ key, value });
    } else {
      node.value.value = value;
    }
  }
  delete(key) {
    const hashKey = this.keys[key];
    delete this.keys[key];
    const bucketLinkedList = this.buckets[hashKey];

    const node = bucketLinkedList.find({
      callback: (nodeValue) => nodeValue.key === key,
    });

    if (node) {
      return bucketLinkedList.delete(node.value);
    }

    return null;
  }
  get(key) {
    const bucketLinkedList = this.buckets[this.hash[key]];
    const node = bucketLinkedList.find({
      callback: (nodeValue) => nodeValue.key === key,
    });
    return node ? node.value.value : undefined;
  }
  has(key) {
    return Object.hasOwnProperty.call(this.keys, key);
  }
  getKeys() {
    return Object.keys(this.keys);
  }
};
